package com.ygq.Impl;


import BO.*;
import DO.*;
import DTO.WorkAnswerDTO;
import VO.WorkStudentAnswerViewVO;
import VO.WorkTest2VO;
import com.ygq.WorkService;
import mapper.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import result.Result;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class WorkServiceImpl implements WorkService {
    @Autowired
    private WorkClassMapper workClassMapper;

    @Autowired
    private WorkStudentStateMapper workStudentStateMapper;

    @Autowired
    private studentMapper studentMapper;

    @Autowired
    private WorkAnswerMapper workAnswerMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private WorkEncodeMapper workEncodeMapper;

    @Autowired
    private WorkChooseMapper workChooseMapper;

    @Autowired
    private WorkJudgeMapper workJudgeMapper;
    
    @Autowired 
    private WorkFillMapper workFillMapper;

    @Autowired
    private WorkMapper workMapper;

    @Autowired
    private WorkFileUploadMapper workFileUploadMapper;

    @Autowired
    private WorkTestTwoDataMapper workTestTwoDataMapper;


    // 根据班级id获取结束时间
    public LocalDateTime getEndTime(Integer classId,Integer workId) {
        return workClassMapper.getEndTimeByClassId(classId,workId);
    }

    // 查询学生试卷提交还是保存状态
    public Integer getStudentState(Integer userId, Integer workId) {
        Integer state = workStudentStateMapper.getStateById(userId, workId);
        if (state==null){
            state = 2;// 2 表示保存，1表示提交 3表示时间已经结束了
        }
        // 先根据用户id获取到那个班级
        Integer classId = studentMapper.getClassIdById(userId);
        LocalDateTime time = workClassMapper.getEndTimeByClassId(classId, workId);
        if (time.isBefore(LocalDateTime.now())){
            state = 3;//表示已经超时了
        }
        return state;
    }

    // 查询学生试卷提交还是保存状态
    public Integer getStudentOldState(Integer userId, Integer workId) {
        return workStudentStateMapper.getStateById(userId, workId);
    }

    // 提交答案
    @Transactional
    public Double submissAnswer(WorkAnswerDTO workAnswerDTO) {
        Integer state = workStudentStateMapper.getStateById(workAnswerDTO.getUserId(), workAnswerDTO.getWorkId());
        if (state != null && state ==1){
            return -0.1;
        }
        String key = "WorkAnswer" + ":" + workAnswerDTO.getWorkId() + ":";

        // 1 声明空数组接收临时存储数组
        int[] chooseAnswer = new int[workAnswerDTO.getChoose().size()];
        int[] judgeAnswer = new  int[workAnswerDTO.getJudge().size()];
        List<List<String>> fillEmptyAnswer = new ArrayList<>();

        String chooseRedisString = stringRedisTemplate.opsForValue().get(key + "1");
        String judgeRedisString = stringRedisTemplate.opsForValue().get(key + "2");
        String fillEmptyRedisString = stringRedisTemplate.opsForValue().get(key+"3");
        // 2 如果redis里面的数据为空,就走数据库进行查询,并将其重新写入到redis中
        if (chooseRedisString == null || judgeRedisString == null || fillEmptyRedisString == null){
            // 2 根据这个题目id分别查询这个测试题目的正确答案，然后存入redis中
            // 2-1 选择题答案查询
            int i = 0;
            for (ChooseAnswerBO chooseAnswerBO : workAnswerDTO.getChoose()) {
                String answer = workAnswerMapper.getChooseAnswerById(chooseAnswerBO.getChooseId());
                if (answer.equals("A")){
                    chooseAnswer[i] = 1;
                }
                if (answer.equals("B")){
                    chooseAnswer[i] = 2;
                }
                if (answer.equals("C")){
                    chooseAnswer[i] = 3;
                }
                if (answer.equals("D")) {
                    chooseAnswer[i] = 4;
                }
                i = i + 1;
            }

            // 2-2 判断题答案查询
            i = 0;
            for (JudgeAnswerBO judgeAnswerBO : workAnswerDTO.getJudge()) {
                Integer answer =  workAnswerMapper.getJudgeAnswerById(judgeAnswerBO.getJudgeId());
                judgeAnswer[i] = answer;
                i++;
            }

            // 2-4 填空题查询
            i = 0;
            for (FillEmptyAnswerBO fillEmptyAnswerBO : workAnswerDTO.getFillEmpty()) {
                List<String> answer = workAnswerMapper.getFillEmptyAnswerById(fillEmptyAnswerBO.getFillEmptyId());
                fillEmptyAnswer.add(answer);
                i++;
            }

            // 2-5 将答案存入redis中,答案命名规则 redis的key名称命名方法：WorkAnswer + ：+ 作业id + : + 对应的题型
            // 1 对应选择题 2 对应判断题 3对应填空题

            String chooseString = Arrays.toString(chooseAnswer);
            stringRedisTemplate.opsForValue().set(key+"1",chooseString);

            String judgeString = Arrays.toString(judgeAnswer);
            stringRedisTemplate.opsForValue().set(key+"2",judgeString);

            stringRedisTemplate.opsForValue().set(key+"3",listOfListsToString(fillEmptyAnswer));

            LocalDateTime endTime = getEndTime(studentMapper.getClassIdById(workAnswerDTO.getUserId()), workAnswerDTO.getWorkId());
//            if (endTime.isBefore(LocalDateTime.now())){
//                // 表示超时，也就是超过截止时间进行提交的，需要进行报错
//                return -1.0;
//            }
            // 设置这三个key的过期时间
            Duration duration = Duration.between(LocalDateTime.now(),endTime);
            // 获取Duration中的秒数部分
            long expirationTimeInSeconds = duration.getSeconds()+15;
            stringRedisTemplate.expire(key+"1", expirationTimeInSeconds, TimeUnit.SECONDS);
            stringRedisTemplate.expire(key+"2", expirationTimeInSeconds, TimeUnit.SECONDS);
            stringRedisTemplate.expire(key+"3", expirationTimeInSeconds, TimeUnit.SECONDS);
        }
        // redis里面的数据不为空,接走redis里面的数据
        else {
            // 移除方括号
            chooseRedisString = chooseRedisString.substring(1, chooseRedisString.length() - 1);
            // 使用 split 方法按逗号分割字符串
            String[] elements = chooseRedisString.split(", ");
            // 使用 IntStream 和 mapToInt 将字符串数组转换为整数数组
            chooseAnswer = Arrays.stream(elements)
                    .mapToInt(Integer::parseInt)
                    .toArray();

            // 移除方括号
            judgeRedisString = judgeRedisString.substring(1, judgeRedisString.length() - 1);
            // 使用 split 方法按逗号分割字符串
            String[] elements_judge = judgeRedisString.split(", ");
            // 使用 IntStream 和 mapToInt 将字符串数组转换为整数数组
            judgeAnswer = Arrays.stream(elements_judge)
                    .mapToInt(Integer::parseInt)
                    .toArray();
            fillEmptyAnswer = csvStringToListOfLists(fillEmptyRedisString);
        }

        // 3 将这个正确答案与学生答案进行比较，并计算总分 将这个答案分级保存，
        double scores = 0.0;
        Double chooseScore = workChooseMapper.getScoreByWorkId(workAnswerDTO.getWorkId());
        Double judgeScore = workJudgeMapper.getScoreByWorkId(workAnswerDTO.getWorkId());
        // 3-1 保存选择题答案,并计算分数
        int k = 0;
        List<WorkAnswerChooseDO> answerChooseDOList = new ArrayList<>();
        for (ChooseAnswerBO chooseAnswerBO : workAnswerDTO.getChoose()) {
            WorkAnswerChooseDO workAnswerChooseDO = new WorkAnswerChooseDO();
            workAnswerChooseDO.setUserId(workAnswerDTO.getUserId());
            workAnswerChooseDO.setWorkId(workAnswerDTO.getWorkId());
            workAnswerChooseDO.setOrder(k+1);
            workAnswerChooseDO.setChooseId(chooseAnswerBO.getChooseId());
            workAnswerChooseDO.setIsRight(0);
            workAnswerChooseDO.setStudentAnswer(0);
            if (chooseAnswerBO.getAnswer()!=null){
                workAnswerChooseDO.setStudentAnswer(chooseAnswerBO.getAnswer());
                workAnswerChooseDO.setIsRight(chooseAnswer[k]==chooseAnswerBO.getAnswer()?1:0);
            }
            workAnswerChooseDO.setRightAnswer(chooseAnswer[k]);
            answerChooseDOList.add(workAnswerChooseDO);
            k++;
            if (workAnswerChooseDO.getIsRight() == 1){
                scores = scores + chooseScore;
            }
        }
        workAnswerMapper.saveChooseAnswer(answerChooseDOList);
        // 3-2 保存判断题答案
        k = 0;
        List<WorkAnswerJudgeDO> workAnswerJudgeDOList = new ArrayList<>();
        for (JudgeAnswerBO judgeAnswerBO : workAnswerDTO.getJudge()) {
            WorkAnswerJudgeDO workAnswerJudgeDO = new WorkAnswerJudgeDO();
            workAnswerJudgeDO.setUserId(workAnswerDTO.getUserId());
            workAnswerJudgeDO.setWorkId(workAnswerDTO.getWorkId());
            workAnswerJudgeDO.setOrder(k+1);
            workAnswerJudgeDO.setJudgeId(judgeAnswerBO.getJudgeId());
            workAnswerJudgeDO.setIsRight(0);
            workAnswerJudgeDO.setStudentAnswer(0);
            if (judgeAnswerBO.getAnswer() != null){
                workAnswerJudgeDO.setStudentAnswer(judgeAnswerBO.getAnswer());
                workAnswerJudgeDO.setIsRight(judgeAnswerBO.getAnswer()==judgeAnswer[k]?1:0);
            }
            workAnswerJudgeDO.setRightAnswer(judgeAnswer[k]);
            workAnswerJudgeDOList.add(workAnswerJudgeDO);
            k++;
            if (workAnswerJudgeDO.getIsRight() == 1){
                scores = scores + judgeScore;
            }
        }
        workAnswerMapper.saveJudgeAnswer(workAnswerJudgeDOList);

        // 3-3 保存程序填空题答案
        k=0;
        int l;
        List<WorkAnswerFillAnswerDO> workAnswerFillAnswerDOList = new ArrayList<>();
        for (FillEmptyAnswerBO fillEmptyAnswerBO : workAnswerDTO.getFillEmpty()) {
            l = 0;// 记录空格顺序
            for (fillEmptyAnswerOrderBO answer : fillEmptyAnswerBO.getAnswers()) {
                WorkAnswerFillAnswerDO workAnswerFillAnswerDO = new WorkAnswerFillAnswerDO();
                workAnswerFillAnswerDO.setUserId(workAnswerDTO.getUserId());
                workAnswerFillAnswerDO.setWorkId(workAnswerDTO.getWorkId());
                workAnswerFillAnswerDO.setOrderQuestion(k+1);
                workAnswerFillAnswerDO.setOrder(l+1);
                workAnswerFillAnswerDO.setFillEmptyId(fillEmptyAnswerBO.getFillEmptyId());
                workAnswerFillAnswerDO.setIsRight(0);
                if (answer.getAnswer() != null){
                    workAnswerFillAnswerDO.setStudentAnswer(answer.getAnswer());
                    workAnswerFillAnswerDO.setIsRight(Objects.equals(answer.getAnswer(), fillEmptyAnswer.get(k).get(l)) ?1:0);
                }
                workAnswerFillAnswerDO.setRightAnswer(fillEmptyAnswer.get(k).get(l));
                workAnswerFillAnswerDO.setScore(answer.getScore());
                l++;
                workAnswerFillAnswerDOList.add(workAnswerFillAnswerDO);
                if (workAnswerFillAnswerDO.getIsRight() == 1){
                    scores = scores + answer.getScore();
                }
            }
            k++;
        }
        workAnswerMapper.saveFillEmptyAnswer(workAnswerFillAnswerDOList);

        // 3-4 保存编程题答案
        k = 0;
        List<WorkAnswerEncodeDO> workAnswerEncodeDOList = new ArrayList<>();
        for (EncodeAnswerBO encodeAnswerBO : workAnswerDTO.getEncode()) {
            encodeAnswerBO.setState((encodeAnswerBO.getState() == null) ? 6 : encodeAnswerBO.getState());
            WorkAnswerEncodeDO workAnswerEncodeDO = new WorkAnswerEncodeDO();
            workAnswerEncodeDO.setUserId(workAnswerDTO.getUserId());
            workAnswerEncodeDO.setWorkId(workAnswerDTO.getWorkId());
            workAnswerEncodeDO.setOrder(k+1);
            workAnswerEncodeDO.setEncodeId(encodeAnswerBO.getEncodeId());
            Double score = workEncodeMapper.getScoreById(encodeAnswerBO.getEncodeId(),workAnswerDTO.getWorkId());
            workAnswerEncodeDO.setScore(score);
            workAnswerEncodeDO.setIsRight(encodeAnswerBO.getState() == 0 ?1:0);
            workAnswerEncodeDO.setState(encodeAnswerBO.getState());
            workAnswerEncodeDOList.add(workAnswerEncodeDO);
            if (workAnswerEncodeDO.getIsRight() == 1){
                scores = scores +score;
            }
            k++;
        }
        workAnswerMapper.saveEncodeAnswer(workAnswerEncodeDOList);

        // 5 计算得分，并将其得分保存到分数表中，将得分作为返回值返回
        WorkScoreDO workScoreDO = new WorkScoreDO();
        workScoreDO.setWorkId(workAnswerDTO.getWorkId());
        workScoreDO.setUserId(workAnswerDTO.getUserId());
        workScoreDO.setStudentScores(scores);
        workScoreDO.setCreateTime(LocalDateTime.now());
        workStudentStateMapper.saveScores(workScoreDO);
        // 6 学生测试状态表修改状态为1
        workStudentStateMapper.updateState(workAnswerDTO.getUserId(),workAnswerDTO.getWorkId(),LocalDateTime.now());

        return scores;
    }

    // 获取学生答案
    public Result<WorkStudentAnswerViewVO> getStudentAnswer(Integer userId, Integer workId) {
        WorkStudentAnswerViewVO workStudentAnswerViewVO = new WorkStudentAnswerViewVO();
        // 第一步，查询学生成绩
        workStudentAnswerViewVO.setScore(workStudentStateMapper.getScoresById(userId,workId));
        // 第二步，查询选择题答案
        workStudentAnswerViewVO.setChooseAnswerViewBOList(workAnswerMapper.getStudentAnswerChooseViewById(userId,workId));
        // 第三步，查询判断题答案
        workStudentAnswerViewVO.setJudgeAnswerViewBOList(workAnswerMapper.getStudentAnswerJudgeViewById(userId, workId));
        // 第四步查询填空题答案
        int fillNumber = workMapper.getFillNumber(workId);
        List<List<FillAnswerViewBO>> fillAnswerViewBOListList = new ArrayList<>();
        for (int i = 0; i < fillNumber; i++) {
            List<FillAnswerViewBO> fillAnswerViewBOList;
            fillAnswerViewBOList = workAnswerMapper.getStudentAnswerFillViewById(userId,workId,i+1);
            fillAnswerViewBOListList.add(fillAnswerViewBOList);
        }
        workStudentAnswerViewVO.setFillAnswerViewBOList(fillAnswerViewBOListList);
        // 第五步，编程题答案查询
        workStudentAnswerViewVO.setEncodeAnswerViewBOList(workAnswerMapper.getStudentAnswerEmptyViewById(userId,workId));
        return Result.success(workStudentAnswerViewVO);
    }

    /**
     * 获取测试2的数据
     * @param workId
     * @param classId
     * @return
     */
    public WorkTest2VO getWorkTest2(Integer workId, Integer classId) {
        WorkTest2VO workTestVO = new WorkTest2VO();
        // 1，先根据workId 在work表查询出主要信息
        WorkDO workDO = workMapper.getByWorkId(workId);
        workTestVO.setStartRange(workDO.getStartRange());
        workTestVO.setEndRange(workDO.getEndRange());
        workTestVO.setFileUploadNumber(workDO.getFileUploadNumber());
        workTestVO.setTitle(workDO.getTitle());
        // 2. 利用workId 查询出题目的主要信息
        workTestVO.setWorkTest2BOList(workFileUploadMapper.getById(workId));
        // 3. 利用classId和workId查询出这个测试是否超时
        LocalDateTime time = workClassMapper.getEndTimeByClassId(classId, workId);
        if (time.isBefore(LocalDateTime.now())){
            workTestVO.setTimeOut(1);
        }else {
            workTestVO.setTimeOut(0);
        }
        return workTestVO;
    }

    /**
     * 保存学生测试2的学生上传数据
     * @param workTestTwoDataDO
     */
    public void saveWorkTest(WorkTestTwoDataDO workTestTwoDataDO) {
        // 如果这个时间这个顺序有题目存在，则只需要修改即可
        if (workTestTwoDataMapper.updateByOrder(workTestTwoDataDO) == 1){
            // 表示修改成功，返回即可
            return;
        };
        workTestTwoDataMapper.save(workTestTwoDataDO);
    }

    /**
     * 获取测试2中的学生分数信息
     * @param workId
     * @param userId
     * @param number
     * @return
     */
    public List<Double> getWorkTest2Score(Integer workId, Integer userId, Integer number) {
        List<WorkTestTwoDataDO> workTestTwoDataDOList = workTestTwoDataMapper.getById(workId,userId);
        List<Double> list = new ArrayList<>();
        int k = 0;

        int flat = 0;// 标识符，来看workTestTwoDataDOList是否到底
        if (workTestTwoDataDOList.size() == k){
            flat = 1;
        }

        for (Integer i = 0; i < number; i++) {
            if (flat == 1){
                list.add((double) -2);
            }
            else if (workTestTwoDataDOList.get(k).getOrder() == i+1){ // 表示workTestTwoDataDOList存在第i+1个题目的数据
                list.add(workTestTwoDataDOList.get(k).getScore());
                k++;
                if (workTestTwoDataDOList.size() == k){
                    flat = 1;
                }
            }else{
                list.add((double) -2);
            }
        }
        return list;
    }

    // 冷处理获取学生答案
    public Result<WorkStudentAnswerViewVO> getStudentAnswerButNull(Integer userId, Integer workId) {
        // 1.先根据workId获取出该套题目有多少题目以及分布
        WorkDO workDO = workMapper.getById(workId);
        WorkStudentAnswerViewVO workStudentAnswerViewVO = new WorkStudentAnswerViewVO();
        workStudentAnswerViewVO.setScore(0.0);
        // 2.冷处理选择题
        // 2-1. 根据workId查询出该套选择题的全部答案
        List<WorkChooseDO> workChooseDOList = workChooseMapper.getByWorkId(workId);

        // 构建正确答案数组
        Integer chooseAnswer[] = new Integer[workDO.getChooseNumber()];
        int i = 0;
        for (WorkChooseDO workChooseDO : workChooseDOList) {
            String answer = workAnswerMapper.getChooseAnswerById(workChooseDO.getChooseId());
            if (answer.equals("A")){
                chooseAnswer[i] = 1;
            }
            if (answer.equals("B")){
                chooseAnswer[i] = 2;
            }
            if (answer.equals("C")){
                chooseAnswer[i] = 3;
            }
            if (answer.equals("D")) {
                chooseAnswer[i] = 4;
            }
            i = i + 1;
        }

        List<ChooseAnswerViewBO> chooseAnswerViewBOList = new ArrayList<>();
        for (Integer j = 0; j < workDO.getChooseNumber(); j++) {
            ChooseAnswerViewBO chooseAnswerViewBO = new ChooseAnswerViewBO();
            chooseAnswerViewBO.setStudentAnswer(0);
            chooseAnswerViewBO.setRightAnswer(chooseAnswer[j]);
            chooseAnswerViewBO.setIsRight(0);
            chooseAnswerViewBOList.add(chooseAnswerViewBO);
        }
        workStudentAnswerViewVO.setChooseAnswerViewBOList(chooseAnswerViewBOList);

        // 3.冷处理判断题
        // 3-1. 根据workId查询出该套选择题的全部答案
        List<WorkJudgeDO> workJudgeDOList = workJudgeMapper.getByWorkId(workId);

        // 构建正确答案数组
        Integer judgeAnswer[] = new Integer[workDO.getJudgeNumber()];
        i = 0;
        for (WorkJudgeDO workJudgeDO : workJudgeDOList) {
            Integer answer = workAnswerMapper.getJudgeAnswerById(workJudgeDO.getJudgeId());
            judgeAnswer[i] = answer;
            i++;
        }

        // 封装正确冷数据
        List<JudgeAnswerViewBO> judgeAnswerViewBOList = new ArrayList<>();
        for (Integer j = 0; j < workDO.getJudgeNumber(); j++) {
            JudgeAnswerViewBO judgeAnswerViewBO = new JudgeAnswerViewBO();
            judgeAnswerViewBO.setStudentAnswer(-1);
            judgeAnswerViewBO.setRightAnswer(judgeAnswer[j]);
            judgeAnswerViewBO.setIsRight(0);
            judgeAnswerViewBOList.add(judgeAnswerViewBO);
        }
        workStudentAnswerViewVO.setJudgeAnswerViewBOList(judgeAnswerViewBOList);

        // 4.程序填空题补充
        List<List<FillAnswerViewBO>> fillAnswerViewBOList = new ArrayList<>();
        // 4-1,根据workId获取到这个填空题的id数据
        List<Integer> fillEmptyIds = workFillMapper.getFillIdByWorkId(workId);
        // 4-2，根据这个填空题id分别查看每道题的答案
        for (int k = 0; k < fillEmptyIds.size(); k++) {
            Integer fillEmptyId = fillEmptyIds.get(k);
            List<FillAnswerViewBO> fillAnswerViewBOS = new ArrayList<>();
            // 答案数据
            List<String> fillEmptyAnswerById = workAnswerMapper.getFillEmptyAnswerById(fillEmptyId);
            for (String s : fillEmptyAnswerById) {
                FillAnswerViewBO fillAnswerViewBO = new FillAnswerViewBO();
                fillAnswerViewBO.setStudentAnswer(null);
                fillAnswerViewBO.setRightAnswer(s);
                fillAnswerViewBO.setIsRight(0);
                fillAnswerViewBOS.add(fillAnswerViewBO);
            }
            fillAnswerViewBOList.add(fillAnswerViewBOS);
        }
        workStudentAnswerViewVO.setFillAnswerViewBOList(fillAnswerViewBOList);

        // 5. 编程题冷处理
        List<EncodeAnswerViewBO> encodeAnswerViewBOList = new ArrayList<>();
        for (Integer integer = 0; integer < workDO.getEncodeNumber(); integer++) {
            EncodeAnswerViewBO encodeAnswerViewBO = new EncodeAnswerViewBO();
            encodeAnswerViewBO.setState(6);
            encodeAnswerViewBOList.add(encodeAnswerViewBO);
        }
        workStudentAnswerViewVO.setEncodeAnswerViewBOList(encodeAnswerViewBOList);

        return Result.success(workStudentAnswerViewVO);
    }

    // 查看填空题是否关联了试卷，是就返回1
    public int getIsRelevancyWork(Integer id) {
        return workFillMapper.getIsRelevancyWork(id)==0?0:1;
    }

    // 判断教师是否打分
    public Integer getIsScores(Integer userId, Integer workId, Integer order) {
        Integer score = workTestTwoDataMapper.getScoresByOrder(userId,workId,order);
        if (score == null){
            return -1;
        }
        return score;
    }


    // list 转化为字符串
    public static String listOfListsToString(List<List<String>> listOfLists) {
        return listOfLists.stream()
                .map(innerList -> String.join(",", innerList))
                .collect(Collectors.joining("\n"));
    }

    // 字符串转化为list
    public static List<List<String>> csvStringToListOfLists(String csvString) {
        List<List<String>> listOfLists = new ArrayList<>();
        String[] lines = csvString.split("\n");
        for (String line : lines) {
            String[] elements = line.split(",");
            listOfLists.add(Arrays.asList(elements));
        }
        return listOfLists;
    }

}
